home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / AppsToGo / DTS.Draw / Drag.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  14.0 KB  |  557 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        Drag.c
  5. ** Written by:    Eric Soldan
  6. **
  7. ** Copyright © 1993 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* You may incorporate this sample code into your applications without
  12. ** restriction, though the sample code has been provided "AS IS" and the
  13. ** responsibility for its operation is 100% yours.  However, what you are
  14. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  15. ** after having made changes. If you're going to re-distribute the source,
  16. ** we require that you make it clear in the source that the code was
  17. ** descended from Apple Sample Code, but that you've made changes. */
  18.  
  19.  
  20.  
  21. /*****************************************************************************/
  22.  
  23.  
  24.  
  25. #include "App.h"            /* Get the application includes/typedefs, etc.    */
  26. #include "App.defs.h"        /* Get various application definitions.            */
  27. #include "App.protos.h"        /* Get the prototypes for the application.        */
  28.  
  29. #ifndef __FOLDERS__
  30. #include <Folders.h>
  31. #endif
  32.  
  33. #ifndef __GESTALTEQU__
  34. #include <GestaltEqu.h>
  35. #endif
  36.  
  37. #ifndef __TREEOBJ2__
  38. #include "TreeObj2.h"
  39. #endif
  40.  
  41. static pascal OSErr DefaultDragTrackingHandler(DragTrackingMessage msg, WindowPtr wnd, void *refcon, DragReference dragRef);
  42. static pascal OSErr DefaultDragReceiveHandler(WindowPtr wnd, void *refcon, DragReference dragRef);
  43.  
  44. static OSErr    GetDragData(FileRecHndl frHndl, Point pt, Handle *retDragData, RgnHandle *retDragRgn);
  45. static Boolean    DropLocationIsFinderTrash(AEDesc *dropLocation);
  46.  
  47. static Boolean    gCanAcceptItems, gWindowHilited;
  48.  
  49.  
  50.  
  51. /*****************************************************************************/
  52. /*****************************************************************************/
  53.  
  54. #ifdef applec
  55. #pragma segment DTSDrawSeg1
  56. #endif
  57.  
  58. /*****************************************************************************/
  59. /*****************************************************************************/
  60.  
  61.  
  62.  
  63. Boolean    DragDropAvailable(void)
  64. {
  65.     long    result;
  66.  
  67.     if (Gestalt(gestaltDragMgrAttr, &result)) return (false);
  68.     
  69.     if (!(result & (1 << gestaltDragMgrPresent))) return(false);
  70.  
  71. #ifdef powerc
  72.     if (!(result & (1 << gestaltPPCDragLibPresent))) return(false);
  73. #endif
  74.  
  75.     return(true);
  76. }
  77.  
  78.  
  79.  
  80. /*****************************************************************************/
  81.  
  82.  
  83.  
  84. OSErr    ManageDragHandlers(WindowPtr window, Boolean install)
  85. {
  86.     OSErr                            err;
  87.     static DragTrackingHandlerUPP    dragTrackingUPP;
  88.     static DragReceiveHandlerUPP    dragReceiveUPP;
  89.  
  90.     if (!DragDropAvailable()) return(paramErr);
  91.  
  92.     if (!dragTrackingUPP) {
  93.         dragTrackingUPP = NewDragTrackingHandlerProc(DefaultDragTrackingHandler);
  94.         dragReceiveUPP  = NewDragReceiveHandlerProc (DefaultDragReceiveHandler);
  95.     }
  96.  
  97.     if (install) {
  98.         err = InstallTrackingHandler(dragTrackingUPP, window, nil);
  99.         if (!err)
  100.             err = InstallReceiveHandler(dragReceiveUPP, window, nil);
  101.         return(err);
  102.     }
  103.     else {
  104.         RemoveTrackingHandler(dragTrackingUPP, window);
  105.         RemoveReceiveHandler(dragReceiveUPP, window);
  106.         return(noErr);
  107.     }
  108. }
  109.  
  110.  
  111.  
  112. /*****************************************************************************/
  113.  
  114.  
  115.  
  116. static pascal OSErr DefaultDragTrackingHandler(DragTrackingMessage msg, WindowPtr wnd, void *refcon, DragReference dragRef)
  117. {
  118. #ifndef __MWERKS__
  119. #pragma unused (refcon)
  120. #endif
  121.  
  122.     unsigned short        count, index;
  123.     unsigned long        flavorFlags, attr;
  124.     ItemReference        theItem;
  125.     RgnHandle            rgn;
  126.     Point                theMouse, localMouse;
  127.     OSErr                err;
  128.     Rect                contRct;
  129.  
  130.     if ((msg != dragTrackingEnterHandler) && (!gCanAcceptItems)) return(noErr);
  131.  
  132.     GetDragAttributes(dragRef, &attr);
  133.  
  134.     switch (msg) {
  135.  
  136.         case dragTrackingEnterHandler:
  137.             /* We get called with this message the first time that a drag enters ANY
  138.             ** window in our application. Check to see if all of the drag items contain
  139.             ** 'DDOC'. We only accept a drag if all of the items in the drag can be accepted. */
  140.  
  141.             gCanAcceptItems = true;
  142.             CountDragItems(dragRef, &count);
  143.  
  144.             for (index = 1; index <= count; index++) {
  145.                 GetDragItemReferenceNumber(dragRef, index, &theItem);
  146.                 err = GetFlavorFlags(dragRef, theItem, 'DDOC', &flavorFlags);
  147.                 if (err != noErr) {
  148.                     gCanAcceptItems = false;
  149.                     break;
  150.                 }
  151.             }
  152.             break;
  153.  
  154.         case dragTrackingEnterWindow:
  155.             /* We receive an EnterWindow message each time a drag enters one of our
  156.             ** application's windows. We initialize our global variables for tracking
  157.             ** the drag through the window. */
  158.  
  159.             break;
  160.  
  161.         case dragTrackingInWindow:
  162.  
  163.             /* We receive InWindow messages as long as the mouse is in one of our windows
  164.             ** during a drag. We draw the window highlighting when we get these messages. */
  165.  
  166.             GetDragMouse(dragRef, &theMouse, 0L);
  167.             localMouse = theMouse;
  168.             GlobalToLocal(&localMouse);
  169.  
  170.             /* Show or hide the window highlighting when the mouse enters or leaves the
  171.             ** TextEdit field in our window (we don't want to show the highlighting when
  172.             ** the mouse is over the window title bar or over the scroll bars). */
  173.  
  174.             GetContentRect(wnd, &contRct);
  175.             if (attr & dragHasLeftSenderWindow) {
  176.                 if (PtInRect(localMouse, &contRct)) {
  177.                     if (!gWindowHilited) {
  178.                         RectRgn(rgn = NewRgn(), &contRct);
  179.                         ShowDragHilite(dragRef, rgn, true);
  180.                         DisposeRgn(rgn);
  181.                     }
  182.                     gWindowHilited = true;
  183.                 } else {
  184.                     if (gWindowHilited)
  185.                         HideDragHilite(dragRef);
  186.                     gWindowHilited = false;
  187.                 }
  188.             }
  189.             break;
  190.  
  191.         case dragTrackingLeaveWindow:
  192.             if ((gWindowHilited) && (attr & dragHasLeftSenderWindow))
  193.                 HideDragHilite(dragRef);
  194.  
  195.             gWindowHilited = false;
  196.             break;
  197.  
  198.         case dragTrackingLeaveHandler:
  199.             break;
  200.  
  201.     }
  202.  
  203.     return(noErr);
  204. }
  205.  
  206.  
  207.  
  208. /*****************************************************************************/
  209.  
  210.  
  211.  
  212. static pascal OSErr DefaultDragReceiveHandler(WindowPtr wnd, void *refcon, DragReference dragRef)
  213. {
  214. #ifndef __MWERKS__
  215. #pragma unused (refcon)
  216. #endif
  217.  
  218.     OSErr                err;
  219.     unsigned short        items, index;
  220.     short                cnum;
  221.     ItemReference        theItem;
  222.     DragAttributes        attr;
  223.     Handle                data;
  224.     Size                dataSize;
  225.     short                mouseDownModifiers, mouseUpModifiers, dragMove;
  226.     Point                mouseLoc, pinnedMouseLoc, initialLoc, locPt;
  227.     TreeObjHndl            dragRoot, root, cobj;
  228.     FileRecHndl            frHndl;
  229.     ClickInfo            click;
  230.     Boolean                change;
  231.  
  232.     if (!gCanAcceptItems) return(dragNotAcceptedErr);
  233.  
  234.     SetPort(wnd);
  235.  
  236.     GetDragAttributes(dragRef, &attr);
  237.     GetDragModifiers(dragRef, 0L, &mouseDownModifiers, &mouseUpModifiers);
  238.  
  239.     dragMove = (
  240.         (attr & dragInsideSenderWindow) &&
  241.         (!((mouseDownModifiers | mouseUpModifiers) & optionKey))
  242.     );
  243.  
  244.     GetDragMouse(dragRef, &mouseLoc, &pinnedMouseLoc);
  245.     locPt = mouseLoc;
  246.     GlobalToLocal(&locPt);
  247.  
  248.     frHndl = (FileRecHndl)GetWRefCon(wnd);
  249.     root   = (*frHndl)->d.doc.root;
  250.     NewDocumentUndo(frHndl);
  251.  
  252.     CountDragItems(dragRef, &items);
  253.  
  254.     change = false;
  255.     for (index = 1; index <= items; ++index) {
  256.  
  257.         /* Get the item's reference number, so we can refer to it. */
  258.  
  259.         GetDragItemReferenceNumber(dragRef, index, &theItem);
  260.  
  261.         /* Try to get the flags for a 'DDOC' flavor. If this returns noErr,
  262.         ** then we know that a 'DDOC' flavor exists in the item. */
  263.  
  264.         err = GetFlavorDataSize(dragRef, theItem, 'DDOC', &dataSize);
  265.  
  266.         if (!err) {
  267.  
  268.             data = NewHandle(dataSize);
  269.             if (!data) return(memFullErr);
  270.  
  271.             HLock(data);
  272.             GetFlavorData(dragRef, theItem, 'DDOC', *data, &dataSize, 0L);
  273.             HUnlock(data);
  274.             dragRoot = NewRootObj(ROOTOBJ, 0);
  275.             err      = HReadTree(dragRoot, data);
  276.             DisposeHandle(data);
  277.             if (err) {
  278.                 DisposeObjAndOffspring(dragRoot);
  279.                 return(err);
  280.             }
  281.  
  282.             if (dragMove) {
  283.                 if (wnd == FrontWindowOfType(kwIsDocument, true)) {
  284.                     GetDragOrigin(dragRef, &initialLoc);
  285.                     click.message = CLICKDRAG;
  286.                     click.offset.h = mouseLoc.h - initialLoc.h;
  287.                     click.offset.v = mouseLoc.v - initialLoc.v;
  288.                     for (cnum = (*root)->numChildren; cnum;) {
  289.                         cobj = GetChildHndl(root, --cnum);
  290.                         if (mDerefCommon(cobj)->selected) {
  291.                             ModifyChild(MOVE_EDIT, root, cnum, true);
  292.                             DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click);
  293.                             change = true;
  294.                         }
  295.                     }
  296.                 }
  297.                 else dragMove = false;
  298.             }
  299.  
  300.             if (!dragMove) {
  301.                 if (!change)
  302.                     DoTreeSelect(root, SELECTOFF);        /* Turn off current document selections. */
  303.                 for (cnum = (*dragRoot)->numChildren; cnum;) {
  304.                     cobj = GetChildHndl(dragRoot, --cnum);
  305.                     click.message = CLICKDRAG;
  306.                     click.offset = locPt;
  307.                     DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click);
  308.                     CopyChild(DRAGDROP_EDIT, dragRoot, cnum, root, 0, true);
  309.                     change = true;
  310.                 }
  311.             }
  312.  
  313.             DisposeObjAndOffspring(dragRoot);
  314.         }
  315.     }
  316.  
  317.     if (change) {
  318.         BeginContent(wnd);
  319.         DoImageDocument(frHndl);
  320.         EndContent(wnd);
  321.         SetWindowDirty(wnd);
  322.         gWindowHilited = false;
  323.     }
  324.  
  325.     return(noErr);
  326. }
  327.  
  328.  
  329.  
  330. /*****************************************************************************/
  331. /*****************************************************************************/
  332. /*****************************************************************************/
  333.  
  334.  
  335.  
  336. static OSErr    GetDragData(FileRecHndl frHndl, Point pt, Handle *retDragData, RgnHandle *retDragRgn)
  337. {
  338.     TreeObjHndl    root, cobj;
  339.     Handle        dragData;
  340.     RgnHandle    dragRgn, rgn;
  341.     short        numChildren, cnum;
  342.     OSErr        err;
  343.     ClickInfo    click;
  344.     Rect        rr;
  345.  
  346.     *retDragData = nil;
  347.     *retDragRgn  = nil;
  348.  
  349.     root     = (*frHndl)->d.doc.root;
  350.     dragData = NewHandle(0);
  351.     dragRgn  = NewRgn();
  352.  
  353.     numChildren = (*root)->numChildren;
  354.     (*root)->numChildren = 0;
  355.     err = HWriteTree(root, dragData);
  356.     (*root)->numChildren = numChildren;
  357.     if (err) {
  358.         DisposeHandle(dragData);
  359.         return(err);
  360.     }
  361.     (*(TreeObjHndl)dragData)->numChildren = mDerefRoot(root)->numSelected;
  362.  
  363.     for (cnum = 0; cnum < (*root)->numChildren; ++cnum) {
  364.         cobj = GetChildHndl(root, cnum);
  365.         if (mDerefCommon(cobj)->selected) {
  366.             DoFTreeMethod(cobj, GETRGNMESSAGE, (long)dragRgn);
  367.             click.message = CLICKDRAG;
  368.             click.offset.h = -pt.h;
  369.             click.offset.v = -pt.v;
  370.             DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click);    /* Set click-point to 0,0. */
  371.             err = HWriteTree(cobj, dragData);
  372.             click.offset = pt;
  373.             DoFTreeMethod(cobj, CLICKMESSAGE, (long)&click);    /* Fix it up. */
  374.             if (err) {
  375.                 DisposeHandle(dragData);
  376.                 DisposeRgn   (dragRgn);
  377.                 return(err);
  378.             }
  379.         }
  380.     }
  381.     if (GetHandleSize((Handle)dragRgn) > 10000) {
  382.         root = (*frHndl)->d.doc.root;
  383.         rr   = GetSelectedArea(root);
  384.         RectRgn(dragRgn, &rr);
  385.         click.message = HITTESTOBJ;
  386.         click.localEvent.where = pt;
  387.         cobj = DoTreeHitTest(root, &click);
  388.         if (cobj) {
  389.             rgn = (RgnHandle)DoTreeObjMethod(cobj, GETRGNMESSAGE, (long)dragRgn);
  390.             DiffRgn(dragRgn, rgn, dragRgn);
  391.             DisposeRgn(rgn);
  392.         }
  393.     }
  394.  
  395.     *retDragData = dragData;
  396.     *retDragRgn  = dragRgn;
  397.     return(noErr);
  398. }
  399.  
  400.  
  401.  
  402. /*****************************************************************************/
  403.  
  404.  
  405.  
  406. static Boolean    DropLocationIsFinderTrash(AEDesc *dropLocation)
  407. {
  408.     OSErr            err;
  409.     AEDesc            dropSpec;
  410.     FSSpec            *theSpec;
  411.     CInfoPBRec        thePB;
  412.     short            trashVRefNum;
  413.     long            trashDirID;
  414.  
  415.     /* Coerce the dropLocation descriptor to an FSSpec. If there's no dropLocation or
  416.     ** it can't be coerced into an FSSpec, then it couldn't have been the Trash. */
  417.  
  418.     if (
  419.         (dropLocation->descriptorType != typeNull) &&
  420.         (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)
  421.     ) {
  422.         HLock(dropSpec.dataHandle);
  423.         theSpec = (FSSpec *)*dropSpec.dataHandle;
  424.  
  425.         /* Get the directory ID of the given dropLocation object. */
  426.  
  427.         thePB.dirInfo.ioCompletion = 0L;
  428.         thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name;
  429.         thePB.dirInfo.ioVRefNum = theSpec->vRefNum;
  430.         thePB.dirInfo.ioFDirIndex = 0;
  431.         thePB.dirInfo.ioDrDirID = theSpec->parID;
  432.  
  433.         err = PBGetCatInfo(&thePB, false);
  434.  
  435.         HUnlock(dropSpec.dataHandle);
  436.         AEDisposeDesc(&dropSpec);
  437.  
  438.         if (err != noErr)
  439.             return(false);
  440.  
  441.         /* If the err is not a directory, it must not be the Trash. */
  442.  
  443.         if (!(thePB.dirInfo.ioFlAttrib & (1 << 4)))
  444.             return(false);
  445.  
  446.         /* Get information about the Trash folder. */
  447.  
  448.         FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID);
  449.  
  450.         /* If the directory ID of the dropLocation object is the same as the directory ID
  451.         ** returned by FindFolder, then the drop must have occurred into the Trash. */
  452.  
  453.         if (thePB.dirInfo.ioDrDirID == trashDirID)
  454.             return(true);
  455.     }
  456.  
  457.     return(false);
  458. }
  459.  
  460.  
  461.  
  462. /*****************************************************************************/
  463.  
  464.  
  465.  
  466. OSErr    DoDrag(FileRecHndl frHndl, EventRecord *event)
  467. {
  468.     OSErr            err;
  469.     Handle            dragData;
  470.     RgnHandle        dragRgn, rgn, oldClip;
  471.     DragReference    dragRef;
  472.     Point            pt;
  473.     Rect            rr;
  474.     DragAttributes    attr;
  475.     AEDesc            dropLoc;
  476.     short            mouseDownModifiers, mouseUpModifiers, dragCopy, i;
  477.     TreeObjHndl        root, cobj;
  478.     WindowPtr        oldPort;
  479.     PicHandle        pic;
  480.  
  481.     if (!DragDropAvailable()) return(paramErr);        /* No mgr, no drag. */
  482.  
  483.     err = NewDrag(&dragRef);
  484.     if (err) return(err);
  485.  
  486.     pt = event->where;
  487.     GlobalToLocal(&pt);
  488.     err = GetDragData(frHndl, pt, &dragData, &dragRgn);
  489.     if (err) return(err);
  490.  
  491.     pt.h = pt.v = 0;
  492.     LocalToGlobal(&pt);
  493.     OffsetRgn(dragRgn, pt.h, pt.v);
  494.  
  495.     HLock(dragData);
  496.     err = AddDragItemFlavor(dragRef, 1, 'DDOC', *dragData, GetHandleSize(dragData), 0);
  497.     DisposeHandle(dragData);
  498.     if (err) {
  499.         DisposeRgn(dragRgn);
  500.         DisposeDrag(dragRef);
  501.         return(err);
  502.     }
  503.  
  504.     oldPort = SetFilePort(frHndl);
  505.     GetClip(oldClip = NewRgn());
  506.     rr = GetDataArea(root = (*frHndl)->d.doc.root);
  507.     pic = OpenPicture(&rr);
  508.     ClipRect(&rr);
  509.     for (i = (*root)->numChildren; i;) {
  510.         cobj = GetChildHndl(root, --i);
  511.         if (mDerefCommon(cobj)->selected)
  512.             DoTreeDraw(cobj, DRAWOBJ);
  513.     }
  514.     ClosePicture();
  515.     SetClip(oldClip);
  516.     DisposeRgn(oldClip);
  517.     SetPort(oldPort);
  518.     HLock((Handle)pic);
  519.     err = AddDragItemFlavor(dragRef, 1, 'PICT', *pic, GetHandleSize((Handle)pic), 0);
  520.     KillPicture(pic);
  521.  
  522.     rr = (*dragRgn)->rgnBBox;
  523.     SetDragItemBounds(dragRef, 1, &rr);
  524.  
  525.     CopyRgn(dragRgn, rgn = NewRgn());
  526.     InsetRgn(rgn, 1, 1);
  527.     DiffRgn(dragRgn, rgn, dragRgn);
  528.     DisposeRgn(rgn);
  529.     err = TrackDrag(dragRef, event, dragRgn);
  530.  
  531.     if ((err) && (err != userCanceledErr)) {
  532.         DisposeDrag(dragRef);
  533.         DisposeRgn(dragRgn);
  534.         return(err);
  535.     }
  536.  
  537.     GetDragAttributes(dragRef, &attr);
  538.     if (!(attr & dragInsideSenderApplication)) {
  539.         GetDropLocation(dragRef, &dropLoc);
  540.         GetDragModifiers(dragRef, 0L, &mouseDownModifiers, &mouseUpModifiers);
  541.         dragCopy = (mouseDownModifiers | mouseUpModifiers) & optionKey;
  542.  
  543.         if ((!dragCopy) && (DropLocationIsFinderTrash(&dropLoc)))
  544.             DoDelete(frHndl);
  545.  
  546.         AEDisposeDesc(&dropLoc);
  547.     }
  548.  
  549.     DisposeDrag(dragRef);
  550.     DisposeRgn(dragRgn);
  551.  
  552.     return(noErr);
  553. }
  554.  
  555.  
  556.  
  557.